/*
 * addon_ddlutil.cpp
 *
 *  Created on: 2010-1-7
 *      Author: gavinkwoe
 */

#include "addon_features.h"

#if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

#include "addon_std.h"
#include "addon_mem.h"
#include "addon_objbase.h"
#include "addon_encoding.h"
#ifndef MPLATFORM_SUPPORT   
	#include <charconv.h>
	#include <coemain.h>
	#include <e32base.h>
	#include <string.h>
#endif
#include "cx_memory.h"
#include "cx_convert.h"
#include "cx_debug.h"
#include "QInstance.h"
/*************************************************************************
* GUID
*************************************************************************/

ADDON_DEFINED_GUID( IAddonEncoding, 1, "C5BF292A-6F5B-4307-AED3-7633A1AD0891" )

/*************************************************************************
* MACRO
*************************************************************************/

#define MAX_GUESS_LEN		(256)
#define DEFAULT_ENCODING	ADDON_ENCODING_UNKNOWN
#define DEFAULT_ORDER		ADDON_LITTLE_ENDIAN

#define __IS_END_CHAR( ch )				(ch) == 0x00
#define __IS_ASCII_CHAR( ch )			((ch) >= 0x01 && (ch) <= 0x7F)

#define __IS_1ST_GB2312( ch )			((ch) >= 0xB0 && (ch) <= 0xF7)
#define __IS_2ND_GB2312( ch )			((ch) >= 0xA0 && (ch) <= 0xFE)
#define __IS_1ST_GB2312_SYM( ch )		((ch) >= 0xA1 && (ch) <= 0xA9)
#define __IS_2ND_GB2312_SYM( ch )		((ch) >= 0xA0 && (ch) <= 0xFF)
#define __IS_GB2312_CHAR( _h, _l ) \
		( \
			(__IS_1ST_GB2312(_h) && __IS_2ND_GB2312(_l)) || \
			(__IS_1ST_GB2312_SYM(_h) && __IS_2ND_GB2312_SYM(_l)) \
		)

#define __IS_1ST_GBK( ch )				((ch) >= 0x81 && (ch) <= 0xFE)
#define __IS_2ND_GBK( ch )				((ch) >= 0x40 && (ch) <= 0xFE)
#define __IS_GBK_CHAR( _h, _l ) \
		( \
			(__IS_1ST_GBK(_h) && __IS_2ND_GBK(_l)) || \
			(__IS_1ST_GB2312_SYM(_h) && __IS_2ND_GB2312_SYM(_l)) \
		)

#define __IS_1ST_BIG5( ch )				((ch) >= 0x81 && (ch) <= 0xFE)
#define __IS_2ND_BIG5( ch )				(((ch) >= 0x40 && (ch) <= 0x7E) || ((ch) >= 0xA1 && (ch) <= 0xFE))
#define __IS_BIG5_CHAR( _h, _l )		(__IS_1ST_BIG5(_h) && __IS_2ND_BIG5(_l))

/*************************************************************************
* STRUCTURE
*************************************************************************/

struct __struct_addon_Encoding_data;
typedef struct __struct_addon_Encoding_data		addon_Encoding_data_t;
typedef struct __struct_addon_Encoding_data *	addon_Encoding_data_ptr_t;

/*************************************************************************
* LOCAL FUNCTIONS
*************************************************************************/

typedef unsigned long	( ADDON_FAR_PROC __find_fptr_t )( unsigned char * buff, unsigned long buff_size, unsigned long buff_off,
															unsigned long * brk_off, unsigned long * skip_bytes );

/*************************************************************************
* DEFINITION
*************************************************************************/

struct __struct_addon_Encoding_data
{
	unsigned long	ref_cnt;	// reference count
	unsigned long	src_enc;
	unsigned long	src_order;
#ifndef MPLATFORM_SUPPORT	
	CCnvCharacterSetConverter *								converter;
	CArrayFix<CCnvCharacterSetConverter::SCharacterSet> *	charsets;
#endif	
};

/*************************************************************************
* LOCAL FUNCTIONS
*************************************************************************/

unsigned long	__CEncoding_Construct( ADDON_REF(IObject) thiz, void * usr_data );
unsigned long	__CEncoding_Destruct( ADDON_REF(IObject) thiz );
unsigned long	__CEncoding_AddRef( ADDON_REF(IObject) thiz );
unsigned long	__CEncoding_Release( ADDON_REF(IObject) thiz );

unsigned long	__CEncoding_Guess( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
											unsigned long * enc, unsigned long * border, unsigned long * bom_len );

unsigned long	__CEncoding_SetEncoding( ADDON_REF(IObject) thiz, unsigned long enc, unsigned long order );

unsigned long	__CEncoding_NextChar( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
												unsigned long * offset );

unsigned long	__CEncoding_PrevBreaker( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
												unsigned long buff_off, unsigned long * offset, unsigned long * next_char );

unsigned long	__CEncoding_NextBreaker( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
												unsigned long buff_off, unsigned long * offset, unsigned long * next_char );

unsigned long	__CEncoding_CharCount( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
												unsigned long * cnt );

unsigned long	__CEncoding_EncodeUCS2( ADDON_REF(IObject) thiz, unsigned short * dst_buff, unsigned long dst_size,
												unsigned char * src_buff, unsigned long src_size,
												unsigned long * conv_len, unsigned long * used_bytes );

unsigned long	__support( QINT charset_id );
static void				__to_encoding( QINT charset_id, unsigned long * enc, unsigned long * order );
static void				__to_charset_id( unsigned long enc, unsigned long order, QINT * char_set );

unsigned long	__utf8_charcnt( unsigned char * buff, unsigned long size );		// UTF8
unsigned long	__ucs2_charcnt( unsigned char * buff, unsigned long size );		// Unicode
unsigned long	__mixed_charcnt( unsigned char * buff, unsigned long size );	// GB? + BIG5 + ASCII

unsigned long	__utf8_next_breaker( unsigned char * buff, unsigned long buff_size, unsigned long * brk_off, unsigned long * skip_bytes );
unsigned long	__ucs2_next_breaker( unsigned char * buff, unsigned long buff_size, unsigned long * brk_off, unsigned long * skip_bytes );
unsigned long	__mixed_next_breaker( unsigned char * buff, unsigned long buff_size, unsigned long * brk_off, unsigned long * skip_bytes );

unsigned long	__utf8_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos );
unsigned long	__ucs2_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos );
unsigned long	__mixed_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos );

// const void * const __coclass_vtbl[] =
// {
// 	// IObject
// 	(void *)__CEncoding_Construct,
// 		(void *)__CEncoding_Destruct,
// 		(void *)__CEncoding_AddRef,
// 		(void *)__CEncoding_Release,
// 		
// 		// IAddonEncoding
// 		(void *)__CEncoding_Guess,
// 		(void *)__CEncoding_SetEncoding,
// 		(void *)__CEncoding_NextChar,
// 		(void *)__CEncoding_PrevBreaker,
// 		(void *)__CEncoding_NextBreaker,
// 		(void *)__CEncoding_CharCount,
// 		(void *)__CEncoding_EncodeUCS2
// };
// 
// const addon_coclass_desc_t __coclass_desc =
// {
// 	(unsigned char *)__coclass_vtbl,
// 		(unsigned long)sizeof( addon_Encoding_data_t )
// };


/*************************************************************************
* LOCAL VARIABLES
*************************************************************************/

static const unsigned long __bpc[16] =
{
	1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 0
};

#define UTF_CHAR_BYTES( __chr )	__bpc[__chr >> 4]

/*************************************************************************
* IMPLEMENTATION
*************************************************************************/

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
#ifndef MPLATFORM_SUPPORT
unsigned long __support( TInt charset_id )
{
	unsigned long support = 0;
	
	switch ( charset_id )
	{
	case KCharacterSetIdentifierAscii:			// ANSI
	case KCharacterSetIdentifierUtf8:			// UTF8
	case KCharacterSetIdentifierGb2312:			// Simple chinese
	case KCharacterSetIdentifierHz:				// Simple chinese
	case KCharacterSetIdentifierGb12345:		// Simple chinese
	case KCharacterSetIdentifierGbk:			// Simple chinese
	case KCharacterSetIdentifierBig5:			// Traditional chinese
	case KCharacterSetIdentifierUnicodeLittle:	// Little Endian Unicode 
	case KCharacterSetIdentifierUnicodeBig:		// Big Endian Unicode 
	case KCharacterSetIdentifierUcs2:			// UCS2 
//	case KCharacterSetIdentifierShiftJis:		// Shift-JIS
//	case KCharacterSetIdentifierIso2022Jp:		// ISO-2022 JP
//	case KCharacterSetIdentifierIso2022Jp1:		// ISO-2022 JP-1
//	case KCharacterSetIdentifierEucJpPacked:	// UEC-JP
//	case KCharacterSetIdentifierJ5:				// JP5
//	case KCharacterSetIdentifierJis:			// JIS
		{
			support = 1;
		}
		break;

	default:
		break;
	}
	
	return support;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
static void __to_encoding( TInt charset_id, unsigned long * enc, unsigned long * order )
{
	unsigned long encoding = DEFAULT_ENCODING;
	unsigned long byte_order = DEFAULT_ORDER;
	
	switch ( charset_id )
	{
	case KCharacterSetIdentifierAscii:		// ANSI
		{
			encoding = ADDON_ENCODING_ASCII;
		}
		break;
		
	case KCharacterSetIdentifierUtf8:		// UTF8
		{
			encoding = ADDON_ENCODING_UTF8;
		}
		break;

	case KCharacterSetIdentifierGb2312:		// Simple chinese
	case KCharacterSetIdentifierHz:			// Simple chinese
		{
			encoding = ADDON_ENCODING_GB2312;
		}
		break;

	case KCharacterSetIdentifierGb12345:	// Simple chinese
		{
			encoding = ADDON_ENCODING_GB12345;
		}
		break;

	case KCharacterSetIdentifierGbk:		// Simple chinese
		{
			encoding = ADDON_ENCODING_GBK;
		}
		break;
		
	case KCharacterSetIdentifierBig5:		// Traditional chinese
		{
			encoding = ADDON_ENCODING_BIG5;
		}
		break;
	
	case KCharacterSetIdentifierUcs2:			// UCS2 
	case KCharacterSetIdentifierUnicodeLittle:	// Little Endian Unicode
		{
			encoding	= ADDON_ENCODING_UCS2;
			byte_order	= ADDON_LITTLE_ENDIAN;
		}
		break;
		
	case KCharacterSetIdentifierUnicodeBig:		// Big Endian Unicode 
		{
			encoding	= ADDON_ENCODING_UCS2;
			byte_order	= ADDON_BIG_ENDIAN;
		}
		break;

//	case KCharacterSetIdentifierShiftJis:		// Shift-JIS
//	case KCharacterSetIdentifierIso2022Jp:		// ISO-2022 JP
//	case KCharacterSetIdentifierIso2022Jp1:		// ISO-2022 JP-1
//	case KCharacterSetIdentifierIso2022Jp1:		// ISO-2022 JP-1
//	case KCharacterSetIdentifierEucJpPacked:	// UEC-JP
//	case KCharacterSetIdentifierJ5:				// JP5
//	case KCharacterSetIdentifierJis:			// JIS
//		{
//			encoding	= ADDON_ENCODING_JIS;
//			byte_order	= ADDON_LITTLE_ENDIAN;
//		}
//		break;
		
	default:
		break;
	}
	
	*enc	= encoding;
	*order	= byte_order;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
static void __to_charset_id( unsigned long enc, unsigned long order, TInt * char_set )
{
	*char_set = 0;
	
	switch ( enc )
	{
	case ADDON_ENCODING_ASCII:		// ANSI
		{
			*char_set = KCharacterSetIdentifierAscii;
		}
		break;

	case ADDON_ENCODING_UTF8:		// UTF8
		{
			*char_set = KCharacterSetIdentifierUtf8;
		}
		break;

	case ADDON_ENCODING_GB2312:		// Simple chinese
		{
			*char_set = KCharacterSetIdentifierGb2312;
		}
		break;

	case ADDON_ENCODING_GB12345:	// Simple chinese
		{
			*char_set = KCharacterSetIdentifierGb12345;
		}
		break;

	case ADDON_ENCODING_GBK:		// Simple chinese
		{
			*char_set = KCharacterSetIdentifierGbk;
		}
		break;
		
	case ADDON_ENCODING_BIG5:		// Traditional chinese
		{
			*char_set = KCharacterSetIdentifierBig5;
		}
		break;

	case ADDON_ENCODING_UCS2:		// UCS2 
		{
			if ( ADDON_BIG_ENDIAN == order )
			{
				*char_set = KCharacterSetIdentifierUnicodeBig;				
			}
			else
			{
				*char_set = KCharacterSetIdentifierUcs2;
			}
		}
		break;

//	case ADDON_ENCODING_JIS:
//		{
//			*char_set = KCharacterSetIdentifierJis;
//		}
//		break;

	default:
		break;
	}
}
#endif

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __utf8_charcnt( unsigned char * buff, unsigned long buff_size )
{
	unsigned long	chr_cnt;
	unsigned long	offset;
	unsigned long	chr_bytes;

	if ( NULL == buff || 0 == buff_size )
		return 0;

    for ( chr_cnt = 0, offset = 0; offset < buff_size; ++chr_cnt )
    {
    	if ( __IS_END_CHAR( buff[offset] ) )
    		break;
    			 
		chr_bytes = UTF_CHAR_BYTES( buff[offset] );
		if ( chr_bytes == 0 )
			break;

		if ( offset + chr_bytes > buff_size )
			break;
		
		offset += chr_bytes;
    }

    return chr_cnt;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __ucs2_charcnt( unsigned char * buff, unsigned long buff_size )
{
	unsigned long		chr_cnt;
	unsigned long		offset;
	
	unsigned long		wsize = (buff_size >> 1);
	unsigned short *	wbuff = (unsigned short *)buff;
	
	for ( chr_cnt = 0, offset = 0; offset < wsize; ++chr_cnt, ++offset )
	{
		if ( __IS_END_CHAR( wbuff[offset] ) )
			break;
	}
	
	return chr_cnt;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __mixed_charcnt( unsigned char * buff, unsigned long buff_size )
{
	unsigned long	chr_cnt;
	unsigned long	offset;

	for ( chr_cnt = 0, offset = 0; offset < buff_size; ++chr_cnt )
	{
		if ( __IS_END_CHAR( buff[offset] ) )
			break;
		
//		if ( __IS_ASCII_CHAR( buff[offset] ) )
//		{
//			offset += sizeof(unsigned char);
//		}
//		else	
		if ( __IS_GB2312_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else if ( __IS_GBK_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else if ( __IS_BIG5_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else
		{
			if ( buff[offset] <= 0x7F && buff[offset + 1] <= 0x7F )
			{
				offset += sizeof(unsigned char);
			}
			else
			{
				offset += sizeof(unsigned short);
			}
		}
	}

    return chr_cnt;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_Construct( ADDON_REF(IObject) thiz, void * usr_data )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	ADDON_UNUSED( usr_data );
	
	if ( NULL == obj_data )
		return ADDON_FAILED;

	obj_data->ref_cnt	= 1;
	obj_data->src_enc	= DEFAULT_ENCODING;
	obj_data->src_order	= DEFAULT_ORDER;
#ifndef MPLATFORM_SUPPORT   
	{
	#undef	__T
	#define	__T CCnvCharacterSetConverter
		CArrayFix<__T::SCharacterSet> *	all_set = __T::CreateArrayOfCharacterSetsAvailableLC( CCoeEnv::Static()->FsSession() );
		if( NULL == all_set )
		{
			CleanupStack::PopAndDestroy();
			return ADDON_FAILED;
		}

		obj_data->charsets = new (ELeave)CArrayFixFlat<__T::SCharacterSet>( 16 );
		//obj_data->charsets = __T::CreateArrayOfCharacterSetsAvailableL( CCoeEnv::Static()->FsSession() );
		if ( NULL == obj_data->charsets )
			return ADDON_FAILED;
		
		/*for ( TInt i = 0;i < obj_data->charsets->Count(); ++i )
		{
			CCnvCharacterSetConverter::SCharacterSet & char_set = obj_data->charsets->At( i );

			if ( 0 == __support( char_set.Identifier() ) )
			{
				obj_data->charsets->Delete(i--);
			}
		}*/

		for ( TInt i = 0, cnt = all_set->Count(); i < cnt; ++i )
		{
			CCnvCharacterSetConverter::SCharacterSet & char_set = all_set->At( i );
			
			if ( 0 != __support( char_set.Identifier() ) )
			{
				obj_data->charsets->AppendL( char_set );
			}
		}
		
		CleanupStack::PopAndDestroy();//all_set

		/*if(all_set)
		{
			all_set->Reset();
			delete all_set;
		}*/

		obj_data->converter = __T::NewL();
		if ( NULL == obj_data->converter )
			return ADDON_FAILED;		
	#undef	__T	
	}
#endif
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_Destruct( ADDON_REF(IObject) thiz )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
#ifndef MPLATFORM_SUPPORT           	
	if ( NULL != obj_data->charsets )
	{
		obj_data->charsets->Reset();
		delete obj_data->charsets;
		obj_data->charsets = NULL;
	}
	if ( obj_data->converter )
	{
		delete obj_data->converter;
		obj_data->converter = NULL;
	}
#endif

	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_AddRef( ADDON_REF(IObject) thiz )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt++;
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_Release( ADDON_REF(IObject) thiz )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt -= 1;

	if ( 0 == obj_data->ref_cnt )
	{
		addon_obj_delete( (void *)thiz );
	}
	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_Guess( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
										unsigned long * enc, unsigned long * order, unsigned long * bom_len )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	if ( NULL == buff || 0 == buff_size || NULL == enc || NULL == order || NULL == bom_len )
		return ADDON_FAILED;
	
	if ( buff_size >= 4 )
	{
		// FF FE 00 00 : UTF-32/UCS-4, little endian. 
		if ( buff[0] == 0xFF && buff[1] == 0xFE && buff[2] == 0x00 && buff[3] == 0x00 )
		{
			*enc		= ADDON_ENCODING_UCS2;
			*order		= ADDON_LITTLE_ENDIAN;
			*bom_len	= 4;
			
			return ADDON_OK;
		}
		
		// 00 00 FE FF : UTF-32/UCS-4, big-endian.
		if ( buff[0] == 0x00 && buff[1] == 0x00 && buff[2] == 0xFE && buff[3] == 0xFF )
		{
			*enc		= ADDON_ENCODING_UCS2;
			*order		= ADDON_BIG_ENDIAN;
			*bom_len	= 4;

			return ADDON_OK;
		}
	}
	
	if ( buff_size >= 3 )
	{
		// EF BB BF : UTF-8 
		if ( buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF )
		{
			*enc		= ADDON_ENCODING_UTF8;
			*order		= ADDON_LITTLE_ENDIAN;
			*bom_len	= 3;
			
			return ADDON_OK;
		}
	}
	
	if ( buff_size >= 2 )
	{
		// FF FE : UTF-16/UCS-2, little endian
		if ( buff[0] == 0xFF && buff[1] == 0xFE )
		{
			*enc		= ADDON_ENCODING_UCS2;
			*order		= ADDON_LITTLE_ENDIAN;
			*bom_len	= 2;
			
			return ADDON_OK;
		}
		
		// FE FF : UTF-16/UCS-2, big endian
		if ( buff[0] == 0xFE && buff[1] == 0xFF )
		{
			*enc		= ADDON_ENCODING_UCS2;
			*order		= ADDON_BIG_ENDIAN;
			*bom_len	= 2;

			return ADDON_OK;
		}
	}
#ifndef MPLATFORM_SUPPORT           	
	{
		TInt	conf_level	= 0;
		TUint	charset_id	= 0;
		TInt	guess_len	= (buff_size > MAX_GUESS_LEN ? MAX_GUESS_LEN : buff_size);
		TPtrC8	buff_ref8( (const TUint8 *)buff, guess_len );

		CCnvCharacterSetConverter::AutoDetectCharacterSetL( conf_level, charset_id, *obj_data->charsets, buff_ref8 );

		__to_encoding( charset_id, enc, order );
		*bom_len	= 0;
	}
#else
	QINT tLength = buff_size;
	unsigned char* cx_src;
	int i,nLenTmp = tLength;	
	
	const char* tSString = (const char*)buff;
	
// 	cx_src = new unsigned char[((nLenTmp + 1)*6)];	
// 	memset(cx_src,0,((nLenTmp + 1)*6));
// 	unsigned short * sTmp3 = (unsigned short * )tSString;
// 	for(i=0;i<nLenTmp/2;i++)
// 	{
// 		char sChar[5] ={0};
// 		cx_sprintf(sChar,"%x",sTmp3[i]);
// 		cx_src[i*6] = (sChar[2] != NULL)?sChar[2]:' ';
// 		cx_src[i*6+1] = (sChar[3] != NULL)?sChar[3]:' ';
// 		cx_src[i*6+2] = ' ';
// 		cx_src[i*6+3] = (sChar[0] != NULL)?sChar[0]:' ';
// 		cx_src[i*6+4] = (sChar[1] != NULL)?sChar[1]:' ';
// 		cx_src[i*6+5] = ' ';
// 	}
//	cx_debug_trace("__CEncoding_Guess tSString[]=%s",cx_src);

	if (cx_IsUTF8(tSString, tLength))
	{
//		cx_debug_trace("__CEncoding_Guess is cx_IsUTF8");
		//ConvUTF8ToUnicode(tPtrTitle, aDest);
		*enc		= ADDON_ENCODING_UTF8;
		*order		= ADDON_LITTLE_ENDIAN;
		*bom_len	= 0;		   		   		   
	}else	
	if(cx_IsGB2312Code(tSString, tLength))
	{
//		cx_debug_trace("__CEncoding_Guess is cx_IsGB2312Code");
		//ConvGB2312ToUnicode(tPtrTitle, aDest);
		*enc		= ADDON_ENCODING_GB2312;
		*order		= ADDON_LITTLE_ENDIAN;
		*bom_len	= 0;		   
	}
	else if (cx_IsGBKCode(tSString, tLength))
	{
//		cx_debug_trace("__CEncoding_Guess is cx_IsGBKCode");
		//ConvGBKToUnicode(tPtrTitle, aDest);
		*enc		= ADDON_ENCODING_GBK;
		*order		= ADDON_LITTLE_ENDIAN;
		*bom_len	= 0;		   		   
	}
	else if (cx_IsUTF8(tSString, tLength))
	{
//		cx_debug_trace("__CEncoding_Guess is cx_IsUTF8 2");
		//ConvUTF8ToUnicode(tPtrTitle, aDest);
		*enc		= ADDON_ENCODING_UTF8;
		*order		= ADDON_LITTLE_ENDIAN;
		*bom_len	= 0;		   		   		   
	}
	else	//default is unicode
	{
//		cx_debug_trace("__CEncoding_Guess default is unicode");
		//aDest.Copy(tPtrTitle);
		*enc		= ADDON_ENCODING_UCS2;
		*order		= ADDON_LITTLE_ENDIAN;
		*bom_len	= 0;		   
	}   
//	delete [] cx_src;
#endif
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __utf8_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos )
{
	unsigned long	i;
	unsigned long	chr_bytes;
	
	for ( i = 0; i < buff_size; ++i )
	{
		chr_bytes = UTF_CHAR_BYTES( buff[i] );
		if ( chr_bytes > 0 )
		{
			*chr_pos = i;
			return 1;
		}
	}
	
	return 0;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __ucs2_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos )
{
	*chr_pos = 0;
	return 1;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __mixed_next_char( unsigned char * buff, unsigned long buff_size, unsigned long * chr_pos )
{
	unsigned long offset;

	for ( offset = 0; offset < buff_size; ++offset )
	{
		if ( __IS_END_CHAR( buff[offset] ) )
			break;

		if ( __IS_GB2312_CHAR( buff[offset], buff[offset + 1] ) )
		{
			*chr_pos = offset;
			return 1;
		}
		else if ( __IS_GBK_CHAR( buff[offset], buff[offset + 1] ) )
		{
			*chr_pos = offset;
			return 1;
		}
		else if ( __IS_BIG5_CHAR( buff[offset], buff[offset + 1] ) )
		{
			*chr_pos = offset;
			return 1;
		}
		else if ( __IS_ASCII_CHAR( buff[offset] ) )
		{
			*chr_pos = offset;
			return 1;
		}
	}

    return 0;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_NextChar( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
											unsigned long * offset )
{
	unsigned long				found = 0;
	addon_Encoding_data_ptr_t	obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	if ( NULL == buff || 0 == buff_size || NULL == offset )
		return ADDON_FAILED;

	switch ( obj_data->src_enc )
	{
	case ADDON_ENCODING_UCS2:
	case ADDON_ENCODING_JIS:
		{
			found = __ucs2_next_char( buff, buff_size, offset );
		}
		break;
		
	case ADDON_ENCODING_ASCII:
	case ADDON_ENCODING_UTF8:
		{
			found = __utf8_next_char( buff, buff_size, offset );
		}
		break;
		
	case ADDON_ENCODING_GB2312:
	case ADDON_ENCODING_GB12345:
	case ADDON_ENCODING_GBK:
	case ADDON_ENCODING_BIG5:
		{
			found = __mixed_next_char( buff, buff_size, offset );
		}
		break;

	default:
		{
			found = __mixed_next_char( buff, buff_size, offset );
		}
		break;
	}
	
	return ( 0 == found ? ADDON_FAILED : ADDON_OK );
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __utf8_next_breaker( unsigned char * buff, unsigned long buff_size,
										unsigned long * brk_off, unsigned long * skip_bytes )
{
	unsigned long	found = 0;
	unsigned long	offset;
	
	for ( offset = 0; offset < buff_size; ++offset )
	{
		if ( __IS_END_CHAR( buff[offset] ) )
			break;
		
		if ( 0x0D == buff[offset] )
		{
			*brk_off = offset;

			if ( (offset + 1 < buff_size) && (0x0A == buff[offset + 1]) )
			{
				*skip_bytes	= offset + 2;
			}
			else
			{
				*skip_bytes	= offset + 1;
			}

			found = 1;
			break;
		}
		else if ( 0x0A == buff[offset] )
		{
			*brk_off = offset;
			
			if ( (offset + 1 < buff_size) && (0x0D == buff[offset + 1]) )
			{
				*skip_bytes	= offset + 2;
			}
			else
			{
				*skip_bytes	= offset + 1;
			}
			
			found = 1;
			break;
		}
	}
	
	return found;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __ucs2_next_breaker( unsigned char * buff, unsigned long buff_size,
										unsigned long * brk_off, unsigned long * skip_bytes )
{
	unsigned long		found = 0;
	unsigned long		offset;
	unsigned long		wsize = (buff_size >> 1);
	unsigned short *	wbuff = (unsigned short *)buff;

	for ( offset = 0; offset < wsize; ++offset )
	{
		if ( __IS_END_CHAR( wbuff[offset] ) )
			break;
		
		if ( 0x0D == wbuff[offset] )
		{
			*brk_off = (offset << 1);

			if ( (offset + 1 < wsize) && (0x0A == wbuff[offset + 1]) )
			{
				*skip_bytes	= ((offset + 2) << 1);
			}
			else
			{
				*skip_bytes	= ((offset + 1) << 1);
			}
			
			found = 1;
			break;
		}
		else if ( 0x0A == wbuff[offset] )
		{
			*brk_off = (offset << 1);
			
			if ( (offset + 1 < wsize) && (0x0D == wbuff[offset + 1]) )
			{
				*skip_bytes	= ((offset + 2) << 1);
			}
			else
			{
				*skip_bytes	= ((offset + 1) << 1);
			}
			
			found = 1;
			break;
		}
	}

	return found;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __mixed_next_breaker( unsigned char * buff, unsigned long buff_size,
										unsigned long * brk_off, unsigned long * skip_bytes )
{
	unsigned long	found = 0;
	unsigned long	offset;

	for ( offset = 0; offset < buff_size; )
	{
		if ( __IS_END_CHAR( buff[offset] ) )
			break;
		
		if ( __IS_ASCII_CHAR( buff[offset] ) )
		{
			if ( 0x0D == buff[offset] )
			{
				*brk_off = offset;

				if ( (offset + 1 < buff_size) && (0x0A == buff[offset + 1]) )
				{
					*skip_bytes	= offset + 2;
				}
				else
				{
					*skip_bytes	= offset + 1;
				}

				found = 1;
				break;
			}
			else if ( 0x0A == buff[offset] )
			{
				*brk_off = offset;
				
				if ( (offset + 1 < buff_size) && (0x0D == buff[offset + 1]) )
				{
					*skip_bytes	= offset + 2;
				}
				else
				{
					*skip_bytes	= offset + 1;
				}
				
				found = 1;
				break;
			}
			
			offset += sizeof(unsigned char);
		}
		else if ( __IS_GB2312_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else if ( __IS_GBK_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else if ( __IS_BIG5_CHAR( buff[offset], buff[offset + 1] ) )
		{
			offset += sizeof(unsigned short);
		}
		else
		{
			if ( buff[offset] <= 0x7F && buff[offset + 1] <= 0x7F )
			{
				offset += sizeof(unsigned char);
			}
			else
			{
				offset += sizeof(unsigned short);
			}
		}
	}
	
	return found;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_PrevBreaker( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
											unsigned long buff_off, unsigned long * brk_off, unsigned long * skip_bytes )
{
	unsigned long	found = 0;
	unsigned long	offset;
	
	for ( offset = buff_off; offset > 0; --offset )
	{
		if ( 0x0D == buff[offset] || 0x0A == buff[offset] )
		{
			*brk_off = offset;
			*skip_bytes	= buff_off - offset;

			found = 1;
			break;
		}
	}
	
	return ( 0 == found ? ADDON_FAILED : ADDON_OK );
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_NextBreaker( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
												unsigned long buff_off, unsigned long * brk_off, unsigned long * skip_bytes )
{
	unsigned long				found;
	addon_Encoding_data_ptr_t	obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );
	
	if ( NULL == obj_data || NULL == buff || 0 == buff_size || NULL == brk_off || NULL == skip_bytes )
		return ADDON_FAILED;

	switch ( obj_data->src_enc )
	{
	case ADDON_ENCODING_UCS2:
	case ADDON_ENCODING_JIS:
		{
			found = __ucs2_next_breaker( &buff[buff_off], (buff_size - buff_off), brk_off, skip_bytes );
		}
		break;
		
	case ADDON_ENCODING_ASCII:
	case ADDON_ENCODING_UTF8:
		{
			found = __utf8_next_breaker( &buff[buff_off], (buff_size - buff_off), brk_off, skip_bytes );
		}
		break;
		
	case ADDON_ENCODING_GB2312:
	case ADDON_ENCODING_GB12345:
	case ADDON_ENCODING_GBK:
	case ADDON_ENCODING_BIG5:
		{
			found = __mixed_next_breaker( &buff[buff_off], (buff_size - buff_off), brk_off, skip_bytes );
		}
		break;

	default:
		{
			found = __mixed_next_breaker( &buff[buff_off], (buff_size - buff_off), brk_off, skip_bytes );
		}
		break;
	}

	return ( 0 == found ? ADDON_FAILED : ADDON_OK );
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_CharCount( ADDON_REF(IObject) thiz, unsigned char * buff, unsigned long buff_size,
											unsigned long * cnt )
{
	unsigned long				length = 0;
	addon_Encoding_data_ptr_t	obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data || NULL == cnt )
		return ADDON_FAILED;

	switch ( obj_data->src_enc )
	{
	case ADDON_ENCODING_UCS2:
	case ADDON_ENCODING_JIS:
		{
			length = __ucs2_charcnt( buff, buff_size );
		}
		break;
		
	case ADDON_ENCODING_ASCII:
	case ADDON_ENCODING_UTF8:
		{
			length = __utf8_charcnt( buff, buff_size );
		}
		break;
		
	case ADDON_ENCODING_GB2312:
	case ADDON_ENCODING_GB12345:
	case ADDON_ENCODING_GBK:
	case ADDON_ENCODING_BIG5:
		{
			length = __mixed_charcnt( buff, buff_size );
		}
		break;

	default:
		{
			length = __mixed_charcnt( buff, buff_size );
		}
		break;
	}

	*cnt = length;
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_SetEncoding( ADDON_REF(IObject) thiz, unsigned long enc, unsigned long order )
{
	addon_Encoding_data_ptr_t obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );
#ifndef MPLATFORM_SUPPORT           
	TInt char_set = 0;
	CCnvCharacterSetConverter::TAvailability avail;
	RFs & rfs = CCoeEnv::Static()->FsSession();
	if ( NULL == obj_data || NULL == obj_data->converter )
		return ADDON_FAILED;

	__to_charset_id( enc, order, &char_set );
	if ( 0 == char_set )
	{
		return ADDON_FAILED;
	}

	avail = obj_data->converter->PrepareToConvertToOrFromL( char_set, rfs );
	if ( avail != CCnvCharacterSetConverter::EAvailable )
	{
		return ADDON_FAILED;
	}

	if ( ADDON_BIG_ENDIAN == order )
	{
		obj_data->converter->SetDefaultEndiannessOfForeignCharacters( CCnvCharacterSetConverter::EBigEndian );
	}
	else
	{
		obj_data->converter->SetDefaultEndiannessOfForeignCharacters( CCnvCharacterSetConverter::ELittleEndian );
	}
#endif
	
	obj_data->src_enc	= enc;
	obj_data->src_order	= order;

	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CEncoding_EncodeUCS2( ADDON_REF(IObject) thiz, unsigned short * dst_buff, unsigned long dst_size,
											unsigned char * src_buff, unsigned long src_size,
											unsigned long * conv_len, unsigned long * used_bytes )
{
	QINT 	rem_bytes;
	QINT	ucs_len;
	unsigned char* cx_src;
	addon_Encoding_data_ptr_t	obj_data = (addon_Encoding_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == dst_buff || NULL == dst_size || NULL == src_buff || NULL == src_size )
		return ADDON_FAILED;

#ifndef MPLATFORM_SUPPORT           	
	TInt 	state = CCnvCharacterSetConverter::KStateDefault;
	TPtr16	dst( (TUint16 *)dst_buff, (TInt)(dst_size / sizeof(unsigned short)) );
	TPtrC8	src( (const TUint8 *)src_buff, (TInt)src_size );


	if ( NULL == obj_data || NULL == obj_data->converter )	
		return ADDON_FAILED;
	rem_bytes = obj_data->converter->ConvertToUnicode( dst, src, state, ucs_len );	
#else	
//    cx_debug_trace("start IAddonEncoding_EncodeUCS2 1");
	if(obj_data->src_enc == ADDON_ENCODING_UCS2)
	{
		memcpy(dst_buff,src_buff,dst_size);
		rem_bytes = 0;
		ucs_len = 0;		
//		cx_debug_trace("start IAddonEncoding_EncodeUCS2 1.2 ADDON_ENCODING_UCS2");
	}
	else if(obj_data->src_enc == ADDON_ENCODING_UTF8)
	{
		//QINT cx_qTUtf8ToUcs2Str(QBYTE *dest,QINT dest_size,QBYTE* src)
		cx_src = new unsigned char[src_size + 4];
		memset(cx_src,0,(src_size+4));
		memcpy(cx_src,src_buff,src_size);
		cx_qTUtf8ToUcs2Str((QBYTE*)dst_buff,dst_size,(unsigned char *)cx_src);
		rem_bytes = 0;
		ucs_len = 0;		
		delete [] cx_src;
//		cx_debug_trace("start IAddonEncoding_EncodeUCS2 1.3 ADDON_ENCODING_UTF8");
	}
	else if(obj_data->src_enc == ADDON_ENCODING_GB2312)  //sanford tmp
	{
		int nLenTmp = 0;
		int i = 0;
		char *sTmp2 = (char*)dst_buff;
//		cx_debug_trace("IAddonEncoding_EncodeUCS2 2 obj_data->src_enc == ADDON_ENCODING_GB2312");
		//int nResult = cx_closeApplication2(dst_buff,dst_size,(char *)src_buff);//cx_gb2312_to_ucs2(dst_buff,dst_size,(char *)src_buff);
		int nResult = cx_gb2312_to_ucs2(dst_buff,dst_size,(char *)src_buff);
		//cx_closeApplication2(1);
//		cx_debug_trace("IAddonEncoding_EncodeUCS2 3 after cx_gb2312_to_ucs2");
		if(nResult != 0)
		{
			cx_debug_trace("cx_gb2312_to_ucs2 Faile Result=%d",nResult);
		}
		nLenTmp = dst_size;
		if(nLenTmp > 255)
		{
			nLenTmp = 200;
//			cx_debug_trace("cx_gb2312_to_ucs2 nLenTmp > 255 dst_size=%d",dst_size);
		}
// 		cx_debug_trace("cx_gb2312_to_ucs2 dst_buff=0x%x",dst_buff);
// 		cx_src = new unsigned char[(nLenTmp + 1)*6];
// 		memset(cx_src,0,((nLenTmp + 1)*6));
// 		for(i=0;i<nLenTmp/2;i++)
// 		{
// 			char sChar[5] ={0};
// 			cx_sprintf(sChar,"%x",dst_buff[i]);
// 			cx_src[i*6] = (sChar[2] != NULL)?sChar[2]:' ';
// 			cx_src[i*6+1] = (sChar[3] != NULL)?sChar[3]:' ';
// 			cx_src[i*6+2] = ' ';
// 			cx_src[i*6+3] = (sChar[0] != NULL)?sChar[0]:' ';
// 			cx_src[i*6+4] = (sChar[1] != NULL)?sChar[1]:' ';
// 			cx_src[i*6+5] = ' ';
// 		}
// 		cx_debug_trace("cx_gb2312_to_ucs2 dst_buff[]=%s",cx_src);
// 		nLenTmp = cx_strlen_w((const unsigned short *)src_buff);
// 		if(nLenTmp > dst_size)
// 		{
// 			nLenTmp = dst_size;
// 		}
// 		cx_debug_trace("cx_gb2312_to_ucs2 src_buff=%d",dst_size);
// 		cx_debug_trace("cx_gb2312_to_ucs2 src_buff=0x%x",src_buff);
// 		memset(cx_src,0,((nLenTmp + 1)*6));
// 		unsigned short * sTmp3 = (unsigned short * )src_buff;
// 		for(i=0;i<nLenTmp/2;i++)
// 		{
// 			char sChar[5] ={0};
// 			cx_sprintf(sChar,"%x",sTmp3[i]);
// 			cx_src[i*6] = (sChar[2] != NULL)?sChar[2]:' ';
// 			cx_src[i*6+1] = (sChar[3] != NULL)?sChar[3]:' ';
// 			cx_src[i*6+2] = ' ';
// 			cx_src[i*6+3] = (sChar[0] != NULL)?sChar[0]:' ';
// 			cx_src[i*6+4] = (sChar[1] != NULL)?sChar[1]:' ';
// 			cx_src[i*6+5] = ' ';
// 		}
// 		cx_debug_trace("cx_gb2312_to_ucs2 src_buff[]=%s",cx_src);
		
		rem_bytes = 0;
		ucs_len = 0;		
		//delete [] cx_src;
	}
	else
	{
#ifndef MPLATFORM_SUPPORT           			
		rem_bytes = obj_data->converter->ConvertToUnicode( dst, src, state, ucs_len );
		ucs_len = dst.Length();
#endif		
//		cx_debug_trace("start IAddonEncoding_EncodeUCS2 1.5 else");
	}
#endif	
	if ( rem_bytes < 0 )
		return ADDON_FAILED;
	ucs_len = (dst_size / sizeof(unsigned short));
	dst_buff[ucs_len] = '\0';
	
	if ( NULL != conv_len )
	{
		*conv_len = (unsigned long)ucs_len;
	}
	
	if ( NULL != used_bytes )
	{
		*used_bytes = src_size - rem_bytes;
	}

	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_encoding( void * reserved )
{
	//static const 
	void * __coclass_vtbl[11];
	//	{;
	// IObject;
	int i=0;		
	__coclass_vtbl[i++] =				(void *)__CEncoding_Construct;
	__coclass_vtbl[i++] =				(void *)__CEncoding_Destruct;
	__coclass_vtbl[i++] =				(void *)__CEncoding_AddRef;
	__coclass_vtbl[i++] =				(void *)__CEncoding_Release;
	
	// IAddonEncoding;
	__coclass_vtbl[i++] =				(void *)__CEncoding_Guess;
	__coclass_vtbl[i++] =				(void *)__CEncoding_SetEncoding;
	__coclass_vtbl[i++] =				(void *)__CEncoding_NextChar;
	__coclass_vtbl[i++] =				(void *)__CEncoding_PrevBreaker;
	__coclass_vtbl[i++] =				(void *)__CEncoding_NextBreaker;
	__coclass_vtbl[i++] =				(void *)__CEncoding_CharCount;
	__coclass_vtbl[i++] =				(void *)__CEncoding_EncodeUCS2;
//	};
	
// 	static const addon_coclass_desc_t __coclass_desc =
// 	{
// 		(unsigned char *)__coclass_vtbl,
// 		(unsigned long)sizeof( addon_Encoding_data_t )
// 	};
	addon_coclass_desc_t __coclass_desc;

	__coclass_desc.vtbl_size	= (unsigned long)sizeof(__coclass_vtbl);
	__coclass_desc.vtbl_funcs	= (unsigned char *)__coclass_vtbl;
	__coclass_desc.priv_size	= (unsigned long)sizeof(addon_Encoding_data_t);

	return ( ADDON_REF(IObject) )addon_obj_new( (addon_coclass_desc_ptr_t)&__coclass_desc, reserved );
}

#else	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_encoding( void * reserved )
{
	ADDON_UNUSED( reserved );
	return NULL;
}

#endif	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)
